home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 12 - 1996 / 12.12 Dec 96 / Flat File Databases / Invoice Example ƒ / Functional ƒ / InvoiceFuncs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-02  |  20.0 KB  |  601 lines  |  [TEXT/CWIE]

  1.  
  2. #include    "InvoiceGlobals.h"
  3. #include     "BTreeDef.h"
  4. #include     "BTreeProtos.h"
  5. #include     "SampleHeader.h"
  6. #include     "Actions.h"
  7. // macros useful to this file only
  8.  
  9. #define        kICustNo 7
  10. #define        kIInvNo 8
  11. #define        kICustName 20
  12. #define        kIPartNum1 6
  13. #define     kIPartQuant1 4
  14. #define        kIPartName1 18
  15. #define        kIPartNum2 5
  16. #define     kIPartQuant2 3
  17. #define        kIPartName2 19
  18. #define        kIPopUp 12
  19. #define        kLoadRelated 2
  20. #define        kIDoIt 1
  21. #define        kIPartPrice1    23
  22. #define        kIPartPrice2    24
  23. #define        kITotal        25
  24.  
  25. #define        kIFind 1
  26. #define        kINext 2
  27. #define        kIPrev 3
  28. #define        kIInsert 4
  29. #define        kFindByCust 5
  30.  
  31. //used for a lot of the dialog work
  32. static short JitemNo;
  33. static short JitemType;
  34. static Handle    Jitem;
  35. static Rect        JBox;
  36.  
  37. // variables used for this file.
  38. // technically, they are global, but we don't export them elsewhere
  39. // because they are not used in any other file
  40.  short         actionErr;
  41.  FileAddr    CustAddr;
  42.  FileAddr     LineItemAddr1;
  43.  FileAddr     LineItemAddr2;
  44.  FileAddr    IPartAddr1;
  45.  FileAddr     IPartAddr2;
  46.  FileAddr    InvoiceAddr;
  47.  short        findingBy = kFindByNumber;
  48.  long        currentInvAddr;
  49.  Str255        currentInvCustName;
  50.  long        currentInvNumber;
  51.  long        currentInvCustNumber;
  52.  
  53. //extra Customer Record, "current record" with respect to these actions
  54.  CustomerType     iCustomer;
  55. //used for temporary calls when loading/updating the Invoice
  56.  PartType        gPartExtra1; 
  57.  PartType        gPartExtra2;
  58.  
  59. //prototypes
  60.  
  61. short CheckCustomer(FileAddr *CustAddr);
  62. short CheckPart(FileAddr *Part1, FileAddr *Part2);
  63. void HandleInvoiceAction(EventRecord *theEvent,short *theItem);
  64. void InactivateEdit(DialogPtr theDialog, short theItem);
  65. void ReactivateEdit(DialogPtr theDialog, short theItem);
  66. void HandleIPopUp (short theItem);
  67. void SetAString(DialogPtr theDialog,short itemNo, Str255 theString);
  68. void SetANumber(DialogPtr theDialog, short itemNo, long theNumber);
  69. void GetAString(DialogPtr theDialog, short itemNo, Str255 theString);
  70. void GetANumber(DialogPtr theDialog, short itemNo, long *theNumber);
  71. short LoadRelated(void);
  72. short HandleDoIt(void);
  73. short LoadAndFixScreen(FileAddr InvAddr);
  74.  
  75.  
  76. // is there a valid entry in the index tree for this customer number
  77. short CheckCustomer(FileAddr *CustAddr){
  78. Str255 tempString;
  79. long    tempLong;
  80. long    resultLong;
  81. short CheckErr = 0;
  82. short tempShort;
  83. GetDialogItem(gInvoiceDialog,kICustNo,&JitemType,&Jitem,&JBox);
  84. GetDialogItemText(Jitem,tempString);
  85. StringToNum(tempString,&tempLong);
  86. CheckErr = Find_Equal(kCustomerNumTree, gInvoiceFCH,(Ptr)&tempLong, (Ptr)&resultLong, CustAddr, kLongCompare);
  87. if (CheckErr != noErr) {
  88.     HandleErrorMsg(CheckErr);
  89.     return CheckErr;
  90.     }
  91. if (tempLong != resultLong) {
  92.     ParamText(tempString, "\pCustomer", "\p", "\p");
  93.     tempShort = Alert(132, NULL);
  94.     return -1;
  95.     }
  96. else 
  97.     return CheckErr;    
  98. }//function
  99.  
  100. // is there a valid entry in the index tree for this part number
  101. short CheckPart(FileAddr *Part1, FileAddr *Part2){
  102. Str255 tempString;
  103. long    tempLong;
  104. long    resultLong;
  105. long    foundAddr;
  106. short CheckErr = 0;
  107. short tempShort;
  108. short extraErr;
  109. short i;
  110. for (i=1; i<3; i++) {
  111.     if (i == 1) {
  112.         JitemNo = kIPartNum1;
  113.         }
  114.     else if (i==2){
  115.         JitemNo = kIPartNum2;
  116.         }
  117.     GetDialogItem(gInvoiceDialog,JitemNo,&JitemType,&Jitem,&JBox);
  118.     GetDialogItemText(Jitem,tempString);
  119.     StringToNum(tempString,&tempLong);
  120.     CheckErr = Find_Equal(kPartNumTree, gInvoiceFCH,(Ptr)&tempLong, (Ptr)&resultLong, &foundAddr, kLongCompare);
  121.     if (i==1) {
  122.         *Part1 = foundAddr;
  123.         }
  124.     else if (i==2){
  125.         *Part2 = foundAddr;
  126.         }
  127.     if (CheckErr != noErr) {
  128.         HandleErrorMsg(CheckErr);
  129.         continue;
  130.         }
  131.     if (tempLong != resultLong) {
  132.         ParamText(tempString, "\pPart", "\p", "\p");
  133.         tempShort = Alert(132, NULL);
  134.         if (i==1) {
  135.             *Part1 = -1;
  136.             }
  137.         else if (i==2){
  138.             *Part2 = -1;
  139.             }
  140.         continue;
  141.         }         
  142.     }//for
  143.     return CheckErr;    
  144. }//function
  145.  
  146.  
  147. // turns an editable text into a static text field
  148. void InactivateEdit(DialogPtr theDialog, short theItem){
  149. short         itemType;
  150. Handle        item;
  151. Rect        box;
  152. GetDialogItem(theDialog, theItem, &itemType, &item, &box);
  153. itemType = statText;
  154. SetDialogItem(theDialog, theItem, itemType, item, &box);
  155. InsetRect(&box, -5, -5);
  156. EraseRect(&box);
  157. InvalThisItemRect(theDialog,theItem);
  158. }
  159.  
  160. // turns a static text field into an editable text field
  161. void ReactivateEdit(DialogPtr theDialog, short theItem){
  162. short         itemType;
  163. Handle        item;
  164. Rect        box;
  165. GetDialogItem(theDialog, theItem, &itemType, &item, &box);
  166. itemType = editText;
  167. SetDialogItem(theDialog, theItem, itemType, item, &box);
  168. InsetRect(&box, -5, -5);
  169. EraseRect(&box);
  170. InvalThisItemRect(theDialog,theItem);
  171.  
  172. }
  173.  
  174.  
  175. // manage interface for the dialog, toggling controls and 
  176. // managing which fields can have data entered in them
  177. void HandleIPopUp(short theItem) {
  178. ControlHandle popControl;
  179. popControl = GetCtlHandle(gInvoiceDialog,kIPopUp);
  180. gInvoiceAction = GetControlValue(popControl);
  181. switch (gInvoiceAction) {
  182.     case kIFind:
  183.         ReactivateEdit(gInvoiceDialog,kIInvNo);
  184.         InactivateEdit(gInvoiceDialog,kIPartNum1);
  185.         InactivateEdit(gInvoiceDialog,kIPartNum2);
  186.         InactivateEdit(gInvoiceDialog,kIPartQuant1);
  187.         InactivateEdit(gInvoiceDialog,kIPartQuant2);
  188.         InactivateEdit(gInvoiceDialog,kICustName);
  189.         InactivateEdit(gInvoiceDialog,kICustNo);
  190.         SelectDialogItemText(gInvoiceDialog, kIInvNo, 0, 0);
  191.         ToggleControl(gInvoiceDialog,1,1);
  192.     case kINext:
  193.     case kIPrev:
  194.         break;
  195.     case kIInsert:
  196.         ReactivateEdit(gInvoiceDialog,kIPartNum1);
  197.         ReactivateEdit(gInvoiceDialog,kIPartNum2);
  198.         ReactivateEdit(gInvoiceDialog,kIPartQuant1);
  199.         ReactivateEdit(gInvoiceDialog,kIPartQuant2);
  200.         InactivateEdit(gInvoiceDialog,kICustName);
  201.         ReactivateEdit(gInvoiceDialog,kICustNo);
  202.         InactivateEdit(gInvoiceDialog,kIInvNo);
  203.         ToggleControl(gInvoiceDialog,1,2);
  204.         SelectDialogItemText(gInvoiceDialog, kICustNo, 0, 0);
  205.         break;
  206.     case kFindByCust:
  207.         InactivateEdit(gInvoiceDialog,kIPartNum1);
  208.         InactivateEdit(gInvoiceDialog,kIPartNum2);
  209.         InactivateEdit(gInvoiceDialog,kIPartQuant1);
  210.         InactivateEdit(gInvoiceDialog,kIPartQuant2);
  211.         ReactivateEdit(gInvoiceDialog,kICustName);
  212.         InactivateEdit(gInvoiceDialog,kICustNo);
  213.         InactivateEdit(gInvoiceDialog,kIInvNo);
  214.         SelectDialogItemText(gInvoiceDialog, kICustName,0,0);
  215.         ToggleControl(gInvoiceDialog,1,1);
  216.         break;
  217.     }//switch
  218. }//function
  219.  
  220. /* when load related is pushed, this function is called.  It will 
  221. 1) check to see if customer entry is valid
  222. 2) check to see if part entry is valid
  223. 3) load these records into current record structs in memory
  224. 4) update the dialog
  225. */
  226. short LoadRelated(void){
  227.     short LoadErr;
  228.     long  theTotal;
  229.     long  theTemp;
  230.     long  converter;
  231.     // if not in insert mode, go no further and put up alert    
  232.     if (gInvoiceAction != kIInsert){
  233.         // load related not working Alert = 133
  234.         short AlertReturn = CautionAlert(133,NULL);
  235.         return -1;
  236.     }// if not in right mode
  237.     // check customer
  238.     LoadErr = CheckCustomer(&CustAddr);
  239.     if ((LoadErr == 0)&&(CustAddr !=-1)) {
  240.         // check part
  241.         LoadErr = CheckPart(&IPartAddr1, &IPartAddr2);
  242.         if ((LoadErr == 0)&&(IPartAddr1 != -1)&&(IPartAddr2 != -1)) {
  243.             // read in customer data
  244.             LoadErr = Read_Data(gInvoiceFCH,sizeof(CustomerType),CustAddr,(Ptr)&iCustomer);
  245.             if (LoadErr != 0) {
  246.                 HandleErrorMsg(LoadErr);
  247.                 return LoadErr;
  248.             }
  249.             // read in part data 1
  250.             LoadErr = Read_Data(gInvoiceFCH, sizeof(PartType), IPartAddr1, (Ptr)&gPartExtra1);
  251.             if (LoadErr != 0) {
  252.                 HandleErrorMsg(LoadErr);
  253.                 return LoadErr;
  254.             }
  255.             // read in part data 2
  256.             LoadErr = Read_Data(gInvoiceFCH, sizeof(PartType), IPartAddr2, (Ptr)&gPartExtra2);
  257.             if (LoadErr != 0) {
  258.                 HandleErrorMsg(LoadErr);
  259.                 return LoadErr;
  260.             }            
  261.             //update the dialog
  262.             //if we're here, a valid customer number is in place, as are two part numbers.
  263.             // just need to put in the names to show we really did it.
  264.             SetAString(gInvoiceDialog,kICustName,iCustomer.CustName);
  265.             SetAString(gInvoiceDialog,kIPartName1,gPartExtra1.PartName);
  266.             SetAString(gInvoiceDialog,kIPartName2,gPartExtra2.PartName);
  267.             GetANumber(gInvoiceDialog,kIPartQuant1,&theTemp);
  268.             StringToNum(gPartExtra1.PartPrice,&converter);
  269.             theTemp = converter*theTemp;
  270.             SetANumber(gInvoiceDialog,kIPartPrice1,theTemp);
  271.             GetANumber(gInvoiceDialog,kIPartQuant2,&theTotal);
  272.             StringToNum(gPartExtra2.PartPrice,&converter);
  273.             theTotal = converter*theTotal;
  274.             SetANumber(gInvoiceDialog,kIPartPrice2,theTotal);
  275.             theTotal = theTotal + theTemp;
  276.             SetANumber(gInvoiceDialog,kITotal,theTotal);
  277.             BeginUpdate(gInvoiceDialog);
  278.             DrawDialog(gInvoiceDialog);
  279.             EndUpdate(gInvoiceDialog);
  280.             //toggle the do it button back to working
  281.             ToggleControl(gInvoiceDialog,1,1);
  282.             
  283.         }//Check Part LoadError
  284.     }//CheckCustomer LoadError
  285. }//function
  286.  
  287. // utility routines for dialogs
  288. void SetAString(DialogPtr theDialog, short itemNo, Str255 theString){
  289.     short itemType;
  290.     Handle item;
  291.     Rect box;
  292.     GetDialogItem(theDialog,itemNo,&itemType,&item, &box);
  293.     SetDialogItemText(item,theString);
  294.     SetDialogItem(theDialog,itemNo,itemType,item,&box);
  295.     InvalThisItemRect(theDialog,itemNo);
  296.     }
  297. void GetAString(DialogPtr theDialog, short itemNo, Str255 theString){
  298.     short itemType;
  299.     Handle item;
  300.     Rect box;
  301.     GetDialogItem(theDialog, itemNo, &itemType, &item, &box);
  302.     GetDialogItemText(item, theString);
  303.     }
  304.     
  305. void SetANumber(DialogPtr theDialog, short itemNo, long theNumber){
  306.     short itemType;
  307.     Handle item;
  308.     Rect box;
  309.     Str255 theString;
  310.     NumToString(theNumber,theString);
  311.     GetDialogItem(theDialog,itemNo,&itemType,&item, &box);
  312.     SetDialogItemText(item,theString);
  313.     SetDialogItem(theDialog,itemNo,itemType,item,&box);
  314.     InvalThisItemRect(theDialog,itemNo);
  315.     }
  316.     
  317. void GetANumber(DialogPtr theDialog, short itemNo, long *theNumber) {
  318.     short itemType;
  319.     Handle item;
  320.     Rect box;
  321.     Str255 theString;
  322.     GetDialogItem(theDialog, itemNo, &itemType, &item, &box);
  323.     GetDialogItemText(item, theString);
  324.     StringToNum(theString,theNumber);
  325.     }
  326.  
  327.  
  328.  
  329.  
  330. // given a valid address of an invoice record, load the invoice, related
  331. //records, and update the screen.
  332. short LoadAndFixScreen(FileAddr InvAddr){
  333.     short LAFErr = noErr;
  334.     long searchLong;
  335.     long foundLong;
  336.     long theTemp, theTotal,converter;
  337.     
  338.     FileAddr foundFileAddr;
  339.     //load invoice
  340.     LAFErr = Read_Data(gInvoiceFCH,kInvoiceSize,InvAddr,(Ptr)&gInvoice);
  341.     if (LAFErr != noErr) {
  342.         HandleErrorMsg(LAFErr);
  343.         return LAFErr;
  344.         }
  345.     // find the file address of line items by finding on the sequence num. of item 1
  346.     // these two items are contiguous in the file, so only need to find the first,
  347.     // then read in twice the struct size from the file
  348.     searchLong = gInvoice.LineItem1;
  349.     LAFErr = Find_Equal(kLineItemTree,gInvoiceFCH,(Ptr)&searchLong, (Ptr)&foundLong,&foundFileAddr,kLongCompare);
  350.     if(searchLong != foundLong) {
  351.         LAFErr = -1;
  352.         HandleErrorMsg(LAFErr);
  353.         return LAFErr;
  354.         };
  355.     // read both at once
  356.     LAFErr = Read_Data(gInvoiceFCH, 2*kLineItemSize, foundFileAddr, (Ptr)gLineItems);
  357.     //load the customer info
  358.     searchLong = gInvoice.CustNo;
  359.     // find the address by finding on the customer number 
  360.     LAFErr = Find_Equal(kCustomerNumTree, gInvoiceFCH, (Ptr)&searchLong, (Ptr)&foundLong, &foundFileAddr, kLongCompare);
  361.     if(searchLong != foundLong) {
  362.         LAFErr = -1;
  363.         HandleErrorMsg(LAFErr);
  364.         return LAFErr;
  365.         };
  366.     LAFErr = Read_Data(gInvoiceFCH, kCustomerSize, foundFileAddr,(Ptr)&iCustomer);
  367.     //load the parts.
  368.     searchLong = gLineItems[0].PartNo;
  369.     // find the part by finding on part # contained in the line item
  370.     LAFErr = Find_Equal(kPartNumTree,gInvoiceFCH, (Ptr)&searchLong,(Ptr)&foundLong, &foundFileAddr,kLongCompare);
  371.     if(searchLong != foundLong) {
  372.         LAFErr = -1;
  373.         HandleErrorMsg(LAFErr);
  374.         return LAFErr;
  375.         };
  376.     LAFErr = Read_Data(gInvoiceFCH, kPartSize, foundFileAddr,(Ptr)&gPartExtra1);
  377.     // now do the same for the second part
  378.     searchLong = gLineItems[1].PartNo;
  379.     LAFErr = Find_Equal(kPartNumTree,gInvoiceFCH, (Ptr)&searchLong,(Ptr)&foundLong, &foundFileAddr,kLongCompare);
  380.     if(searchLong != foundLong) {
  381.         LAFErr = -1;
  382.         HandleErrorMsg(LAFErr);
  383.         return LAFErr;
  384.         };
  385.     LAFErr = Read_Data(gInvoiceFCH, kPartSize, foundFileAddr,(Ptr)&gPartExtra2);
  386. //Manage the dialog appearance; just hack stuff
  387.     SetANumber(gInvoiceDialog,kIInvNo,gInvoice.InvoiceNumber);
  388.     SetANumber(gInvoiceDialog,kICustNo,gInvoice.CustNo);
  389.     SetANumber(gInvoiceDialog,kIPartNum1,gLineItems[0].PartNo);
  390.     SetANumber(gInvoiceDialog,kIPartNum2,gLineItems[1].PartNo);
  391.     SetAString(gInvoiceDialog,kICustName,iCustomer.CustName);
  392.     SetAString(gInvoiceDialog,kIPartName1,gPartExtra1.PartName);
  393.     SetAString(gInvoiceDialog,kIPartName2,gPartExtra2.PartName);
  394.     SetANumber(gInvoiceDialog,kIPartQuant1,gLineItems[0].NumItems);
  395.     SetANumber(gInvoiceDialog,kIPartQuant2,gLineItems[1].NumItems);
  396.     StringToNum(gPartExtra1.PartPrice,&converter);
  397.     theTemp = converter*gLineItems[0].NumItems;
  398.     SetANumber(gInvoiceDialog,kIPartPrice1,theTemp);
  399.     StringToNum(gPartExtra2.PartPrice,&converter);
  400.     theTotal = converter*gLineItems[1].NumItems;
  401.     SetANumber(gInvoiceDialog,kIPartPrice2,theTotal);
  402.     theTotal = theTotal + theTemp;
  403.     SetANumber(gInvoiceDialog,kITotal,theTotal);
  404.  
  405.     
  406. }//function
  407.  
  408.  
  409. short HandleDoIt(void) {
  410. // basically a switch statement that handles the different actions
  411. short doItErr;
  412. FileAddr LineItemsAddr;
  413. Str255     TempString;
  414. long    TempLong;
  415. long    searchLong;
  416. long    foundLong;
  417. FileAddr foundAddr;
  418. FileAddr prevAddr;
  419. Str255    foundString;
  420.     switch (gInvoiceAction) {
  421.     case kIInsert:
  422.         //assumes valid part and customer data. This is valid because Load related
  423.         //has already been called
  424.         
  425.         //fill in fields of line items
  426.         // put the part number in the line item fields
  427.         gLineItems[0].PartNo = gPartExtra1.PartNo;
  428.         gLineItems[1].PartNo = gPartExtra2.PartNo;
  429.         // fill in the quantities
  430.         GetANumber(gInvoiceDialog,kIPartQuant1,&TempLong);
  431.         gLineItems[0].NumItems = TempLong;
  432.         GetANumber(gInvoiceDialog,kIPartQuant2,&TempLong);
  433.         gLineItems[1].NumItems = TempLong;
  434.         BlockMove((Ptr)gPartExtra1.PartPrice,(Ptr)gLineItems[0].ItemPrice,6);
  435.         BlockMove((Ptr)gPartExtra2.PartPrice,(Ptr)gLineItems[1].ItemPrice,6);
  436.         //issue a sequence number for the line items
  437.         (Handle)gSequenceHandle = GetResource(kSRType,kSRID);
  438.         HLock((Handle)gSequenceHandle);
  439.         (**gSequenceHandle).LineItems++;
  440.         gLineItems[0].LineItemNo = gInvoice.LineItem1 = (**gSequenceHandle).LineItems;
  441.         (**gSequenceHandle).LineItems++;
  442.         gLineItems[1].LineItemNo = gInvoice.LineItem2 = (**gSequenceHandle).LineItems;
  443.         //all fields of the line items are filled in, and some of the invoice
  444.         //issue a sequence # for the invoice
  445.         (**gSequenceHandle).Invoices++;
  446.         gInvoice.InvoiceNumber = (**gSequenceHandle).Invoices;
  447.         HUnlock((Handle)gSequenceHandle);
  448.         ChangedResource((Handle)gSequenceHandle);
  449.         WriteResource((Handle)gSequenceHandle);
  450.         //fill in the customer # field of the invoice struct
  451.         gInvoice.CustNo = iCustomer.CustNo;
  452.         // now allocate space and start writing data, entering keys.
  453.         doItErr = Get_Bytes(gInvoiceFCH,&LineItemsAddr, 2*kLineItemSize);
  454.         if (doItErr != noErr) {
  455.             HandleErrorMsg(doItErr);
  456.             return doItErr;
  457.             }//real program would do a lot of cleaning up.
  458.         //short cut:  enter both line items together
  459.         doItErr = Write_Data(gInvoiceFCH,2*kLineItemSize,LineItemsAddr,(Ptr)gLineItems);
  460.         if (doItErr != noErr) {
  461.             HandleErrorMsg(doItErr);
  462.             return doItErr;
  463.             }//real program would do a lot of cleaning up.
  464.         doItErr = Get_Bytes(gInvoiceFCH,&InvoiceAddr, kInvoiceSize);
  465.         if (doItErr != noErr) {
  466.             HandleErrorMsg(doItErr);
  467.             return doItErr;
  468.             }//real program would do a lot of cleaning up.
  469.         doItErr = Write_Data(gInvoiceFCH,kInvoiceSize, InvoiceAddr, (Ptr)&gInvoice);
  470.         //data is entered. Now enter keys. always enter data first.
  471.         //better to have orphan record than key pointing to nowhere.
  472.         //enter key to the invoice by num.
  473.         doItErr = Insert_Key(kInvoiceTree,kUniqueKeys,gInvoiceFCH,(Ptr)&gInvoice.InvoiceNumber,InvoiceAddr,kLongCompare);
  474.         // this is one of the most critical lines of code in the program.
  475.         //uses customer name as key, point to "record address" of Invoice Number
  476.         doItErr = Insert_Key(kInvoiceCustTree,kDuplicateKeys,gInvoiceFCH, (Ptr)&iCustomer.CustName,gInvoice.InvoiceNumber,kPStringCompare);
  477.         //insert the two line item keys.
  478.         doItErr = Insert_Key(kLineItemTree,kUniqueKeys,gInvoiceFCH,(Ptr)&gLineItems[0].LineItemNo,LineItemsAddr,kLongCompare);
  479.         doItErr = Insert_Key(kLineItemTree,kUniqueKeys, gInvoiceFCH,(Ptr)&gLineItems[1].LineItemNo,LineItemsAddr+4,kLongCompare);
  480.         SetANumber(gInvoiceDialog,kIInvNo,gInvoice.InvoiceNumber);
  481.         ToggleControl(gInvoiceDialog,1,2);
  482.         // need this stuff for proper actions of next/previous calls
  483.         currentInvAddr = InvoiceAddr;
  484.         BlockMove((Ptr)&iCustomer.CustName,(Ptr)currentInvCustName,256);
  485.         currentInvNumber = gInvoice.InvoiceNumber;
  486.         currentInvCustNumber = iCustomer.CustNo;
  487.         //phew!
  488.         break;
  489.     case kIFind :
  490.         /* simple find.  Find the invoice by looking up the main invoice
  491.         address (the sequence number) in the appropriate tree*/
  492.         GetANumber(gInvoiceDialog,kIInvNo,&searchLong);
  493.         doItErr = Find_Equal(kInvoiceTree, gInvoiceFCH,(Ptr)&searchLong,(Ptr)&foundLong, &foundAddr, kLongCompare);
  494.         findingBy = kFindByNumber;
  495.         if ((doItErr == noErr)&&(foundAddr!=-1)){
  496.             doItErr = LoadAndFixScreen(foundAddr);
  497.             InvoiceAddr = foundAddr;
  498.             currentInvAddr = foundAddr;
  499.             currentInvNumber = gInvoice.InvoiceNumber;
  500.             }
  501.         break;
  502.     case kINext :
  503.         // see comments under kIFind, kFindByCust
  504.         if (findingBy ==kFindByNumber){ 
  505.             prevAddr = currentInvAddr;
  506.             searchLong = currentInvNumber;
  507.             doItErr = Find_Next(kInvoiceTree,gInvoiceFCH,(Ptr)&searchLong,prevAddr,(Ptr)&foundLong,&foundAddr, kLongCompare);
  508.             }
  509.         else {
  510.             prevAddr = currentInvCustNumber;
  511.             BlockMove((Ptr)currentInvCustName,(Ptr)TempString,256);
  512.             doItErr = Find_Next(kInvoiceCustTree, gInvoiceFCH,(Ptr)TempString,prevAddr,(Ptr)foundString,&foundAddr,kPStringCompare);
  513.             searchLong = foundAddr;
  514.             currentInvCustNumber = searchLong;
  515.             doItErr = Find_Equal(kInvoiceTree, gInvoiceFCH,(Ptr)&searchLong,(Ptr)&foundLong, &foundAddr, kLongCompare);
  516.             InvoiceAddr = foundAddr;
  517.  
  518.             }
  519.         if ((doItErr == noErr)&&(foundAddr!=-1)){
  520.             doItErr = LoadAndFixScreen(foundAddr);
  521.             InvoiceAddr = foundAddr;
  522.             currentInvAddr = foundAddr;
  523.             if (findingBy == kFindByNumber)
  524.                 currentInvNumber = foundLong;
  525.             else {
  526.                 BlockMove((Ptr)foundString,(Ptr)currentInvCustName,256);
  527.                 }
  528.             }
  529.         break;
  530.     case kIPrev :
  531.         // see comments under kIFind, kFindByCust
  532.         if (findingBy ==kFindByNumber){ 
  533.             prevAddr = currentInvAddr;
  534.             searchLong = currentInvNumber;            
  535.             doItErr = Find_Previous(kInvoiceTree,gInvoiceFCH,(Ptr)&searchLong,prevAddr,(Ptr)&foundLong,&foundAddr, kLongCompare);
  536.             }
  537.         else {
  538.             prevAddr = currentInvCustNumber;
  539.             BlockMove((Ptr)currentInvCustName,(Ptr)TempString,256);
  540.             doItErr = Find_Previous(kInvoiceCustTree, gInvoiceFCH,(Ptr)TempString,prevAddr,(Ptr)foundString,&foundAddr,kPStringCompare);
  541.             searchLong = foundAddr;
  542.             currentInvCustNumber = searchLong;
  543.             doItErr = Find_Equal(kInvoiceTree, gInvoiceFCH,(Ptr)&searchLong,(Ptr)&foundLong, &foundAddr, kLongCompare);
  544.             }
  545.         if ((doItErr == noErr)&&(foundAddr!=-1)){
  546.             doItErr = LoadAndFixScreen(foundAddr);
  547.             InvoiceAddr = foundAddr;
  548.             currentInvAddr = foundAddr;
  549.             if (findingBy == kFindByNumber)
  550.                 currentInvNumber = foundLong;
  551.             else
  552.                 BlockMove((Ptr)foundString,(Ptr)currentInvCustName,256);
  553.             }
  554.  
  555.         break;
  556.     case kFindByCust :
  557.         // Get the name of the customer for the search
  558.         GetAString(gInvoiceDialog,kICustName,TempString);
  559.         prevAddr = 0;
  560.         // look for the customer in the kInvoiceCustTree.  The returned four
  561.         // byte "address" is actually the sequence number of the invoice
  562.         doItErr = Find_Next(kInvoiceCustTree, gInvoiceFCH,(Ptr)TempString,prevAddr,(Ptr)&foundString, &foundAddr, kPStringCompare);
  563.         searchLong = foundAddr;
  564.         currentInvCustNumber = searchLong;
  565.         // now find the true address of the invoice by searching the invoice
  566.         // sequence number tree with the foundAddr from the above call as the key
  567.         doItErr = Find_Equal(kInvoiceTree, gInvoiceFCH,(Ptr)&searchLong,(Ptr)&foundLong, &foundAddr, kLongCompare);
  568.         findingBy = kFindByName;
  569.         if ((doItErr == noErr)&&(foundAddr!=-1)){
  570.             doItErr = LoadAndFixScreen(foundAddr);
  571.             InvoiceAddr = foundAddr;
  572.             currentInvAddr = foundAddr;
  573.             BlockMove((Ptr)foundString,(Ptr)currentInvCustName,256);
  574.             }
  575.         break;
  576.  
  577.     default:
  578.         break;
  579.     }//switch
  580. }//function
  581.  
  582. void HandleInvoiceAction(EventRecord *theEvent,short *theItem){
  583.     
  584.     switch (*theItem) {
  585.         case kIPopUp:
  586.             HandleIPopUp(*theItem);
  587.             break;
  588.         case kLoadRelated:
  589.             actionErr = LoadRelated();
  590.             break;
  591.         case kIDoIt:
  592.             actionErr = HandleDoIt();
  593.             break;
  594.     }//switch
  595.     // irrespective of the action, update the dialog when done
  596.     BeginUpdate(gInvoiceDialog);
  597.     DrawDialog(gInvoiceDialog);
  598.     EndUpdate(gInvoiceDialog);
  599.  
  600. return;
  601. }